#include <yaml-cpp/yaml.h>
#include <yaml-cpp/yaml.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <vector>
#include <utility>

using namespace std;

#include "TApplication.h"
#include "TFile.h"
#include "TTree.h"
#include "TRandom3.h"
#include "TMath.h"

#include "setup.h"
// bool isSigS = true;
bool isSigS = false;

void SwapBytes(unsigned char *buf, int n)
{
	for (int i = 0; i < n / 2; i++)
	{
		auto temp = buf[i];
		buf[i] = buf[n - 1 - i];
		buf[n - 1 - i] = temp;
	}
}
template <typename T>
T GetNum(unsigned char *buf, int n)
{
	T value = 0;
	for (int i = n - 1; i >= 0; i--)
	{
		value |= (T)buf[i] << ((n - 1 - i) * 8);
	}
	return value;
}

enum FrameType
{

	BEGIN_NORMAL_DATA = 0x8100,		 // 普通数据帧头//可能跨时间戳 8100
	END_NORMAL_DATA = 0x8101,		 // 普通结束帧头//一个波段信号的结束 8101
	BEGIN_WHOLE_NOMAL_DATA = 0x8102, // 开始普通数据帧头//每个时间戳的开头 8102
	BEGIN_WHOLE_EMPTY_DATA = 0x8104, // 空数据帧头//每个时间戳开头 8104
	END_EMPTY_DATA = 0x8105,		 // 结束空数据帧头//一个波段空信号的结束 8105
	BEGIN_EMPTY_DATA = 0x8106,		 // 开始空数据帧头//可能跨时间戳 8106
	END_WHOLE_DATA = 0x5aa5			 // 结束普通数据帧头//结束一个时间戳信号 5AA5

};
void Raw2Root_ToF()
{
	int i = 0, j = 0, k = 0;
	int lFram = 0;

	clock_t start, finish;
	
	for(auto sRun_ToF:finalFileName)
	{
			start = clock();
			string sBin="../RawData/"+sRun_ToF+".dat";
			string sRoot="../RootData/ToF_"+sRun_ToF+".root";
			printf("\n**********Now converting %s to %s!**********\n\n", sBin.c_str(), sRoot.c_str());

			TFile *fRoot = new TFile(sRoot.c_str(), "RECREATE");
			TTree *treeRaw_ToF = new TTree("treeRaw_ToF", "tree of raw ToF data");

			int nSig_ToF = 0;
			short iBd_ToF = 0, ch_ToF[MaxSig_ToF] = {0}, shift_ToF[MaxSig_ToF] = {0}, fine_ToF[MaxSig_ToF] = {0};
			long long tsSlc_ToF = 0, coarse_ToF[MaxSig_ToF] = {0};

			treeRaw_ToF->Branch("sRun_ToF", &sRun_ToF);

			treeRaw_ToF->Branch("iBd_ToF", &iBd_ToF, "iBd_ToF/S");
			treeRaw_ToF->Branch("tsSlc_ToF", &tsSlc_ToF, "tsSlc_ToF/L");
			treeRaw_ToF->Branch("nSig_ToF", &nSig_ToF, "nSig_ToF/I");
			treeRaw_ToF->Branch("ch_ToF", ch_ToF, "ch_ToF[nSig_ToF]/S");
			treeRaw_ToF->Branch("shift_ToF", shift_ToF, "shift_ToF[nSig_ToF]/S");
			treeRaw_ToF->Branch("coarse_ToF", coarse_ToF, "coarse_ToF[nSig_ToF]/L");
			treeRaw_ToF->Branch("fine_ToF", fine_ToF, "fine_ToF[nSig_ToF]/S");
			treeRaw_ToF->Branch("EventNum",&EventNum,"EventNum/L");
			if (isSigS)
			{
				int nSigs_ToF = 0;
				short chs_ToF[nSigs_ToF] = {0};
				short shifts_TOF[nSigs_ToF] = {0};
				short fines_TOF[nSigs_ToF] = {0};
				long long coarses_TOF[nSigs_ToF] = {0};
				long long tsSlcs_TOF = 0;
				treeRaw_ToF->Branch("n_Sigs_ToF", &nSigs_ToF, "nSig_ToF/I");
				treeRaw_ToF->Branch("chs_ToF", chs_ToF, "ch_ToF[nSig_ToF]/S");
				treeRaw_ToF->Branch("shifts_ToF", shifts_TOF, "shift_ToF[nSig_ToF]/S");
				treeRaw_ToF->Branch("coarses_ToF", coarses_TOF, "coarse_ToF[nSig_ToF]/L");
				treeRaw_ToF->Branch("fines_ToF", fines_TOF, "fine_ToF[nSig_ToF]/S");
				treeRaw_ToF->Branch("tsSlcs_ToF", &tsSlcs_TOF, "tsSlc_ToF/L");
			}

			FILE *fBin = fopen(sBin.c_str(), "rb");
			if (!fBin)
			{
				cout << "Cannot open " << sBin << endl;
				fRoot->Close();
				delete fRoot;
				continue;
			}

			unsigned char buf[16] = {0};
			int nEvents = 0;
			while (!feof(fBin))
			{
				memset(buf, 0, sizeof(buf));
				fread(buf, sizeof(unsigned char), 2, fBin);
				SwapBytes(buf, 2);
				int header = GetNum<int>(buf, 2) & 0xFFFF;
				// int header = int(buf[0] << 8 | buf[1]);
				// cout << "header: " << header << endl;
				if (header == FrameType::BEGIN_EMPTY_DATA || header == FrameType::BEGIN_WHOLE_EMPTY_DATA || header == FrameType::END_EMPTY_DATA)
				{
					memset(buf, 0, sizeof(buf));
					fseek(fBin, 10, SEEK_CUR);

					fread(buf, sizeof(unsigned char), 2, fBin);
					SwapBytes(buf, 2);
					int end = GetNum<int>(buf, 2);
					// cout << "end: " << end << endl;
					if (end != FrameType::END_WHOLE_DATA)
					{
						cerr << "Error: FrameType::END_WHOLE_DATA, end is" << end << endl;
					}

					fseek(fBin, 2, SEEK_CUR);
					continue;
				}
				else if (header == FrameType::BEGIN_NORMAL_DATA || header == FrameType::BEGIN_WHOLE_NOMAL_DATA || header == FrameType::END_NORMAL_DATA)
				{
					memset(buf, 0, sizeof(buf));
					fread(buf, sizeof(unsigned char), 3, fBin);
					SwapBytes(buf, 3);
					lFram = GetNum<int>(buf, 3) & 0xFFFFFF;

					// cout << "lFram: " << lFram << endl;

					nSig_ToF = (lFram - 14) / 8;
					if (nSig_ToF > MaxSig_ToF)
					{
						cerr << "[Error] nSig_ToF > MaxSig_ToF, nSig_ToF is" << nSig_ToF << endl;
						memset(buf, 0, sizeof(buf));
						fread(buf, sizeof(unsigned char), 16, fBin);
						for (int i = 0; i < 16; i++)
						{
							std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)buf[i];
						}
						cout << dec << endl;
						break;
					}

					memset(buf, 0, sizeof(buf));
					fread(buf, sizeof(unsigned char), 6, fBin);
					SwapBytes(buf, 6);

					tsSlc_ToF = GetNum<long long>(buf, 6) & 0xFFFFFFFFFFFF;
					// cout << "tsSlc_ToF: " << tsSlc_ToF << endl;
					memset(buf, 0, sizeof(buf));
					fread(buf, sizeof(unsigned char), 1, fBin);
					iBd_ToF = int(buf[0]);

					// cout << "iBd_ToF: " << iBd_ToF << endl;

					for (int iSig = 0; iSig < nSig_ToF; iSig++)
					{
						memset(buf, 0, sizeof(buf));
						fread(buf, sizeof(unsigned char), 8, fBin);
						SwapBytes(buf, 8);
						ch_ToF[iSig] = int(buf[0] >> 4);
						// cout << "ch_ToF[iSig] = " << ch_ToF[iSig] << endl;
						shift_ToF[iSig] = GetNum<short>(buf, 2) & 0x0FFF;
						coarse_ToF[iSig] = GetNum<long long>(buf + 3, 4) & 0xFFFFFFFF;
						fine_ToF[iSig] = buf[7];
						// cout << "fine_ToF[iSig] = " << fine_ToF[iSig] << endl;
						nEvents++;
						EventNum++;
						if (nEvents % 10000000 == 0)
							std::cout << "nEvents: " << nEvents << std::endl;
					}
					memset(buf, 0, sizeof(buf));
					fread(buf, sizeof(unsigned char), 2, fBin);
					SwapBytes(buf, 2);
					if (GetNum<int>(buf, 2) != FrameType::END_WHOLE_DATA)
					{
						fseek(fBin, -14, SEEK_CUR);
						memset(buf, 0, sizeof(buf));

						fread(buf, sizeof(unsigned char), 14, fBin);
						cout << "[Error] bad end: ";
						for (int i = 0; i < 14; ++i)
						{
							std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)buf[i];
						}
						cout << dec << endl;
						memset(buf, 0, sizeof(buf));
						// fseek(fBin, -2, SEEK_CUR);

						// cout << endl;
					}

					if (nSig_ToF % 2 == 1)
					{
						fseek(fBin, 10, SEEK_CUR);
					}

					else if (nSig_ToF % 2 == 0)
					{
						fseek(fBin, 2, SEEK_CUR);
					}

					if (nSig_ToF > 0)
						treeRaw_ToF->Fill();
				}
				else
				{
					// memset(buf, 0, sizeof(buf));
					// cout << "Error: header, header is" << endl;
					// fseek(fBin, 14, SEEK_CUR);
					fread(buf, sizeof(unsigned char), 14, fBin);
					// fseek(fBin, 14, SEEK_CUR);
					// cout << "jump " << endl;
					// fread(buf, sizeof(unsigned char), 16, fBin);
					// cout << "[Error] " << "There is a error header: ";
					// for (int i = 0; i < 16; ++i)
					// {
					// 	std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)buf[i];
					// }
					// cout << endl;
					// memset(buf, 0, sizeof(buf));
					// fseek(fBin, 16, SEEK_CUR);

					// break;
				}
			}

			fclose(fBin);
			fRoot->cd();
			treeRaw_ToF->Write("", TObject::kOverwrite);
			fRoot->Close();
			delete fRoot;

			finish = clock();
			cout << "Total Events : " << nEvents << endl;
			cout << "\nTime for processing Run#" << sRun_ToF << " is: "
				 << double(finish - start) / CLOCKS_PER_SEC << " s\n\n";
		

		

	}
	// fileName.close();
}

int main(int argc, char **argv)
{
	Raw2Root_ToF();
	return 0;
}
